/*

* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Smart-Shop开源商城系统/ Java商城-首选电商平台系统 请务必保留此注释头信息
* |     开源地址: https://gitee.com/ningbo-qishan/gruul-mall
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     可正常分享和学习源码,未经授权 不可商用！
* |     商业版中台购买/开源版商业授权 联系技术客服
* |     官网:  https://www.73app.cn/
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Copyright (c) 2016-2999 宁波启山智软科技有限公司
* |     版权所有 ,侵权必究！
* ------------------------------------------------------------------------

*/
package com.medusa.gruul.common.core.helper;

import cn.hutool.core.util.IdUtil;
import com.medusa.gruul.common.core.auth.model.User;
import com.medusa.gruul.common.core.auth.model.constant.ClaimsKeys;
import com.medusa.gruul.common.core.auth.model.constant.Headers;
import com.medusa.gruul.common.core.config.Jackson;
import com.medusa.gruul.common.core.config.JwtProperties;
import io.jsonwebtoken.*;
import lombok.RequiredArgsConstructor;

import java.util.Date;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;

/**
 * @author 张治保
 * date 2021/12/2
 */
public class JwtHelper {

    private static TimeUnit ttlTimeUnit;
    public static TokenHelper tokenHelper;
    public static TokenHelper refeshTokenHelper;

    /**
     * 生成 token与refreshToken
     */
    public static AccessToken token(User user){
        Token token = tokenHelper.generate(user);

        user.setAvatar(null).setGender(null).setLanguage(null).setNickname(null);
        Token refreshToken = refeshTokenHelper.generate(user);

        return new AccessToken()
            .setTtlTimeUnit(JwtHelper.ttlTimeUnit)
            .setToken(token)
            .setRefreshToken(refreshToken);
    }

    public static void init(JwtProperties properties){
        JwtHelper.ttlTimeUnit = properties.getTtlTimeUnit();

        JwtProperties.Token token = properties.getToken();
        JwtHelper.tokenHelper = new TokenHelper(token.getSignKey(),token.getTtl(), Headers.TOKEN);

        JwtProperties.Token refreshToken = properties.getRefreshToken();
        JwtHelper.refeshTokenHelper = new TokenHelper(refreshToken.getSignKey(),refreshToken.getTtl(),Headers.REFRESH_TOKEN);
    }


    @RequiredArgsConstructor
    public static class TokenHelper {
        private final String signKey;
        private final  long expiration;
        private final String issuer;

        private  Token generate(User user) {
            Date nowDate = new Date();
            Date expireDate = new Date(nowDate.getTime() + JwtHelper.ttlTimeUnit.toMillis(expiration));
            final String jti = IdUtil.fastSimpleUUID();
            String token =  Jwts.builder()
                .setId(jti)
                .setSubject(user.getUserId())
                .setIssuer(issuer)
                .setIssuedAt(nowDate)
                .setExpiration(expireDate)
                .setClaims(
                    new HashMap<String, Object>(2) {
                        {
                            put(ClaimsKeys.USER, Jackson.writeValueAsString(user));
                            put(ClaimsKeys.JTI, jti);
                        }
                    }
                )
                .signWith(SignatureAlgorithm.HS256, signKey)
                .compact();

            return new Token()
                .setJti(jti)
                .setToken(token)
                .setTtl(expiration);
        }



        /**
         * 校验签名是否正确
         */
        public boolean verify(String token) {
            try {
                Jwts.parser()
                    .setSigningKey(signKey)
                    .parseClaimsJws(token);
                return true;
            } catch (JwtException e) {
                return false;
            }
        }
        /**
         * 获取payload 部分内容（即要传的信息）
         * 使用方法：如获取userId：getClaim(token).get("userId");
         */
        public Claims getClaim(String token) {
            return Jwts.parser()
                    .setSigningKey(signKey)
                    .parseClaimsJws(token)
                    .getBody();
        }

    }

}
